/**********************************************************************************************************************
 *
 * Project:    mGameEngine
 * File:       terraintile.cpp
 * Author:     karooolek
 * Created on: Jun 28, 2009
 *
 **********************************************************************************************************************/

#include "terraintile.h"

namespace mGameEngine
{
namespace Game
{

using namespace Graphics;

TerrainTile::TerrainTile(Terrain *terrain, const Vector2 &position, uint8 lod) :
    Mesh(),
    _terrain(terrain), _position(position), _lod(lod)
{    
    // get terrain params
    const Vector3 &size = _terrain->getHeightField()->getSize();
    float tileSize = _terrain->getTileSize();
    float res = _terrain->getResolution() * (_lod+1);
    uint n = ceil(tileSize / res)+1;

    // create vertices
    _vertices.resize(n*n);
    for(uint x = 0; x != n; ++x)
    {
        for(uint y = 0; y != n; ++y)
        {
            Vertex &v = _vertices[x + n * y];
            Vector2 p = position + Vector2(x, y) * res;
            v.position = Vector3(p, _terrain->getHeightField()->getHeightAt(p));
            v.normal = _terrain->getHeightField()->getNormalAt(p);
            v.texCoords[0] = p / Vector2(size);
        }
    }

    // create group
    _groups.resize(1);
    Group &group = _groups[0];
    group.strips.resize(2);
    
    // create material
    group.material = new TexturedMaterial(_terrain->getTexture());

    // create surface strips
    Strip &surf = group.strips[0];
    for(uint x = 0; x != n-1; ++x)
    {
        for(uint y = 0; y != n; ++y)
        {
            surf.vertices.push_back(x + n*y);
            surf.vertices.push_back(x+1 + n*y);
        }
        surf.vertices.push_back(x+1 + n*(n-1));
        surf.vertices.push_back(x+1);
    }

    // create skirt
    Strip &skirt = group.strips[1];
    uint k = _vertices.size();
    _vertices.resize(k + 4*(n-1));
    uint x, y;
    for(x = y = 0; x != n-1; ++x)
    {
        _vertices[k] = _vertices[x + y*n];
        _vertices[k].position.z = 0.0f;
        skirt.vertices.push_back(x + y*n);
        skirt.vertices.push_back(k++);
    }
    for(; y != n-1; ++y)
    {
        _vertices[k] = _vertices[x + y*n];
        _vertices[k].position.z = 0.0f;
        skirt.vertices.push_back(x + y*n);
        skirt.vertices.push_back(k++);
    }
    for(; x != 0; --x)
    {
        _vertices[k] = _vertices[x + y*n];
        _vertices[k].position.z = 0.0f;
        skirt.vertices.push_back(x + y*n);
        skirt.vertices.push_back(k++);
    }
    for(; y != 0; --y)
    {
        _vertices[k] = _vertices[x + y*n];
        _vertices[k].position.z = 0.0f;
        skirt.vertices.push_back(x + y*n);
        skirt.vertices.push_back(k++);
    }
    skirt.vertices.push_back(0);
    skirt.vertices.push_back(n*n);

    // bonding sphere
    _updateBoundingSphere();
}

TerrainTile::~TerrainTile()
{
    delete _groups.front().material;

    if(_lowerLodMesh)
    {
        delete _lowerLodMesh;
    }
}

void TerrainTile::generateLowerLODMeshes(uint8 levels, float vertReduction)
{
    // can't generate
    if(!levels)
    {
        return;
    }

    _lowerLodMesh = new TerrainTile(_terrain, _position, _lod+1);
    return _lowerLodMesh->generateLowerLODMeshes(levels-1, vertReduction);
}

}
}

